package com.henry.base.concurrency;

import org.junit.Test;

public class RingBuffer2<T> {
    private static final int bufferSize = 1<<23;
    private Object[] buffer = new Object[bufferSize];
    private long head = 0;
    private long tail = 0;

    /**
     * 如果head==tail，说明ringBuffer为空--》不可读
     *
     * @return
     */
    private boolean empty() {
        return head == tail;
    }

    /**
     * 如果tail+1==head或者tail+1==head+bufferSize  说明ringBuffer满了，不可写
     * 下面用tail+1对bufferSize取模，是比较巧的算法
     *
     * @return
     */
    private boolean full() {
        return (tail + 1 - bufferSize) == head;
    }

    public boolean put(T v) {
        if (full()){
            System.out.println("ringbuffer is full-->"+v);
            return false;
        }
        buffer[(int) (tail % bufferSize)] = v;
        tail = tail + 1;
        return true;
    }

    public T get() {
        if (empty()) {
            System.out.println("ringbuffer is empty");
            return null;
        }
        Object result = buffer[(int) (head % bufferSize)];
        head = head + 1;
        return (T) result;
    }

    public Object[] getAll() {
        if (empty()) {
            return new Object[0];
        }
        long copyTail = tail;
        int cnt = (int) (copyTail - head);
        Object[] result = new Object[cnt];
        if (head < copyTail) {
            for (int i = 0; i < cnt; i++) {
                result[i] = buffer[(int) ((head + i) % bufferSize)];
            }
        }
        head = copyTail;
        return result;
    }

    @Test
    public void fun1() throws InterruptedException {
        RingBuffer2<Integer> ringBuffer2 = new RingBuffer2();

        Thread thread = new Thread(()->{
//            Thread.sleep(1);
            int count =0;
            while (true) {
//                count++;
                Integer n = ringBuffer2.get();
                try {
                    if (n == null) {
                        if(count>1000000)
                            return;
//                        Thread.sleep(1000);
//                        System.out.println("ringbuffer is empty");
                    } else {
                        count++;
//                        System.out.println(n);
//                        Thread.sleep(3000);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
        thread.start();
        for (int i = 0; i < 10000000; i++) {
            ringBuffer2.put(i);
//            Thread.sleep(1);
        }
        thread.join();
    }
}
